#include "StdAfx.h"
#include "GeometricMeanTreeNode.h"
#include "exceptions.h"
#include "ComputationalTreeNodeVisitor.h"

using CollabRC::Bot::AI::ComputationalTreeNode;
using CollabRC::Bot::AI::GeometricMeanTreeNode;
using CollabRC::Bot::AI::OperationTreeNode;

/**
 * @brief Creates a new GeometricMeanTreeNode which operates on the specified branches
 * @param lhs the left hand side of the computation
 * @param rhs the right hand side of the computation
 */
GeometricMeanTreeNode::GeometricMeanTreeNode(const ComputationalTreeNode& lhs, const ComputationalTreeNode& rhs)
:OperationTreeNode(lhs, rhs)
{
}

/**
 * @brief Creates a new GeometricMeanTreeNode from the branches of the
 * specified OperationTreeNode
 * @param copy the OperationTreeNode from which this object should be copied
 */
GeometricMeanTreeNode::GeometricMeanTreeNode(const OperationTreeNode& copy)
:OperationTreeNode(copy)
{
}

/**
 * @brief Destroys this GeometricMeanTreeNode and frees associated resources
 */
GeometricMeanTreeNode::~GeometricMeanTreeNode(void)
{
}

/** {@inheritDoc} */
CollabRC::Bot::AI::ComputationalTreeNode* GeometricMeanTreeNode::Clone() const
{
    return new GeometricMeanTreeNode(*this);
}

float GeometricMeanTreeNode::PerformOperation(float lhs, float rhs) const
{
    if (lhs < 0 || rhs < 0)
    {
        CollabRC::Bot::AI::IllegalOperationException ex("Attempt to compute a geometric mean using a negative input");
        throw ex;
    }
    else 
    {
        return std::pow(lhs * rhs, 0.5f);
    }
}

GeometricMeanTreeNode::Factory GeometricMeanTreeNode::factory;

ComputationalTreeNode* GeometricMeanTreeNode::Factory::Instantiate(const ComputationalTreeNode &lhs, const ComputationalTreeNode &rhs) const
{
    return new GeometricMeanTreeNode(lhs, rhs);
}

void GeometricMeanTreeNode::Accept(CollabRC::Bot::AI::ComputationalTreeNodeVisitor& visitor)
{
    OperationTreeNode::Accept(visitor);
    visitor.Visit(*this);
}
